package com.ebo.httpcall4j.core.retry;

import com.ebo.httpcall4j.core.model.HttpCallResponse;
import com.ebo.httpcall4j.core.processor.HttpCallProcessor;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

import java.io.IOException;

/**
 * 重试拦截器，根据请求的 retryable 标志和 RetryStrategy 执行重试逻辑。
 */
public class RetryInterceptor implements Interceptor {

    private final RetryStrategy defaultRetryStrategy;

    public RetryInterceptor(RetryStrategy retryStrategy) {
        this.defaultRetryStrategy = retryStrategy;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        // 检查是否有自定义重试策略或是否启用了可重试标志
        RetryStrategy customRetryStrategy = request.tag(RetryStrategy.class);
        Boolean isRetryable = request.tag(Boolean.class);
        HttpCallProcessor processor = request.tag(HttpCallProcessor.class);

        if (customRetryStrategy == null && (isRetryable == null || !isRetryable)) {
            return chain.proceed(request);
        }

        RetryStrategy effectiveStrategy = (customRetryStrategy != null) ? customRetryStrategy : defaultRetryStrategy;

        int maxRetries = effectiveStrategy.getMaxRetries();
        long initialDelay = effectiveStrategy.getRetryDelayMillis();
        long currentDelay = initialDelay;
        int tryCount = 0;
        Response response = null;
        IOException lastException = null;

        while (tryCount <= maxRetries) {
            tryCount++;
            if (response != null) {
                response.close();
            }

            try {
                response = chain.proceed(request);
                lastException = null;
            } catch (IOException e) {
                lastException = e;
                if (tryCount > maxRetries) {
                    throw e;
                }
            }

            if (lastException == null) { // 网络调用成功，获得了响应
                // 优先判断网络状态，如果网络层面失败（如5xx），则直接进入重试
                if (!response.isSuccessful()) {
                    // 非2xx响应，继续循环以进行重试
                } else {
                    // 网络状态成功（2xx），接着判断业务是否成功
                    boolean isBusinessSuccess;
                    if (processor != null) {
                        // 使用 HttpCallProcessor 定义的业务成功逻辑
                        ResponseBody responseBody = response.body();
                        String bodyString = responseBody.string(); // 消费响应体
                        HttpCallResponse callResponse = toHttpCallResponse(response, bodyString);
                        isBusinessSuccess = processor.isSuccess(callResponse);

                        // 重新创建响应，因为原始响应体已被消费
                        response = response.newBuilder()
                                .body(ResponseBody.create(bodyString, responseBody.contentType()))
                                .build();
                    } else {
                        // 如果没有处理器，并且网络状态是2xx，我们认为业务是成功的
                        isBusinessSuccess = true;
                    }

                    if (isBusinessSuccess) {
                        return response; // 业务也成功，返回最终响应
                    }
                }
            }

            // 如果不成功或发生IO异常，并且还有重试次数，则等待后重试
            if (tryCount <= maxRetries) {
                try {
                    Thread.sleep(currentDelay);
                    currentDelay = (long) (currentDelay * effectiveStrategy.getBackoffMultiplier());
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new IOException("Retry interrupted", e);
                }
            }
        }

        if (lastException != null) {
            throw lastException;
        }

        return response; // 返回最后一次的响应
    }

    /**
     * 将 OkHttp 的 Response 转换为 HttpCallResponse。
     *
     * @param response OkHttp 响应
     * @param body     响应体字符串
     * @return HttpCallResponse
     */
    private HttpCallResponse toHttpCallResponse(Response response, String body) {
        HttpCallResponse callResponse = new HttpCallResponse();
        callResponse.setStatusCode(response.code());
        callResponse.setBody(body);
        callResponse.setOriginalBody(body);
        return callResponse;
    }
}